﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Text;
using System.Collections;
using System.ComponentModel;

namespace ResourceBlender_Express {
    /// <summary>
    /// Represents meta data in a PO file entry
    /// PO specification at http://www.gnu.org/software/autoconf/manual/gettext/PO-Files.html
    /// </summary>
    public class POMetaData : INotifyPropertyChanged {
        private string context = null,
                       untranslatedPlural = null,
                       translatedString = null,
                       untranslatedString = null;
        private List<string> extractedComments,
                             references,
                             flags;
        private Dictionary<string, string> translatorsComments = null;
        private Dictionary<int, Dictionary<string, string>> translatedPlurals = null;

        /// <summary>
        /// Gets or sets the programmer's comments (extracted from the source code)
        /// </summary>
        /// <value>The programmers comments.</value>
        public List<string> ExtractedComments { 
            get { return extractedComments; }
            set {
                extractedComments = value;
                OnPropertyChanged("ExtractedComments");
            }
        }

        /// <summary>
        /// Gets or sets the translator's comments
        /// </summary>
        /// <value>The translator's comments.</value>
        public Dictionary<string, string> TranslatorsComments { 
            get { return translatorsComments; }
            set {
                translatorsComments = value;
                OnPropertyChanged("TranslatorsComments");
            }
        }

        /// <summary>
        /// Gets or sets the source code reference to which this entry applies.
        /// </summary>
        /// <value>The reference.</value>
        public List<string> References {
            get { return references; }
            set {
                references = value;
                OnPropertyChanged("References");
            }
        }

        /// <summary>
        /// Gets or sets the flags.
        /// </summary>
        /// <value>The flags.</value>
        public List<string> Flags { 
            get { return flags; }
            set {
                flags = value;
                OnPropertyChanged("Flags");
            }
        }

        /// <summary>
        /// Gets or sets the untranslated string.
        /// </summary>
        /// <value>The untranslated string.</value>
        public string UntranslatedString {
            get { return untranslatedString; }
            set {
                untranslatedString = value;
                OnPropertyChanged("UntranslatedString");
            }
        }

        /// <summary>
        /// Gets or sets the translated string.
        /// </summary>
        /// <value>The translated string.</value>
        public string TranslatedString { 
            get { return translatedString; }
            set {
                translatedString = value;
                OnPropertyChanged("TranslatedString");
            }
        }

        /// <summary>
        /// Gets or sets the context of the untranslated string, which is needed if more than one entry has the same untranslated string.
        /// </summary>
        /// <value>The context.</value>
        public string Context {
            get { return context; }
            set {
                context = value;
                OnPropertyChanged("Context");
            }
        }

        /// <summary>
        /// Gets or sets the untranslated plural (null if none exists).
        /// </summary>
        /// <value>The untranslated plural.</value>
        public string UntranslatedPlural {
            get { return untranslatedPlural; }
            set {
                untranslatedPlural = value;
                OnPropertyChanged("UntranslatedPlural");
            }
        }

        /// <summary>
        /// Gets or sets the translated plurals for this entry.
        /// <Number, <languageCode, Translation>>
        /// </summary>
        /// <value>The translated plurals.</value>
        public Dictionary<int, Dictionary<string, string>> TranslatedPlurals {
            get { return translatedPlurals; }
            set {
                translatedPlurals = value;
                OnPropertyChanged("TranslatedPlurals");
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="POMetaData"/> class.
        /// </summary>
        public POMetaData() {
            extractedComments = new List<string>();
            translatorsComments = new Dictionary<string, string>();
            references = new List<string>();
            flags = new List<string>();
            untranslatedString = string.Empty;
            translatedString = string.Empty;
        }

        /// <summary>
        /// Gets a textual representation of this meta data including source comments, references and flags which can be stored in an element comments field
        /// Does NOT include translators' comments
        /// </summary>
        /// <returns></returns>
        public string ToCommentsField() {
            StringBuilder buffer = new StringBuilder();
            if(ExtractedComments.Count > 0) {
                foreach(string comment in ExtractedComments) {
                    buffer.Append("#. ").Append(comment).Append("\n");
                }
            }
            if(References.Count > 0) {
                foreach(string reference in References) {
                    buffer.Append("#: ").Append(reference).Append("\n");
                }
            }
            if(Flags.Count > 0) {
                foreach(string flag in Flags) {
                    buffer.Append("#, ").Append(flag).Append("\n");
                }
            }
            if(context != null) {
                buffer.Append("msgctxt \"").Append(context).Append("\"");
            }
            return buffer.ToString();
        }

        /// <summary>
        /// Parses source comments, references, flags and the msgctxt from PO entry meta data.
        /// Does NOT parse translator's comments or translation data.
        /// </summary>
        /// <param name="rawMetaData">The raw meta data.</param>
        /// <returns>An object containing the meta data</returns>
        public static POMetaData Parse(string rawMetaData) {
            POMetaData data = new POMetaData();
            if(rawMetaData != null && rawMetaData.Length > 0) {
                string[] lines = rawMetaData.Split('\n');
                foreach(string line in lines) {
                    if(line.Length < 4) {
                        continue;
                    }
                    switch(line.Substring(0, 2)) {
                        case "#.":
                            data.ExtractedComments.Add(line.Substring(2).Trim());
                            break;
                        case "#:":
                            data.References.Add(line.Substring(2).Trim());
                            break;
                        case "#,":
                            data.Flags.Add(line.Substring(2).Trim());
                            break;
                        default:
                            if(line.StartsWith("msgctxt")) {
                                if(line == "msgctxt \"\"") {
                                    data.Context = string.Empty;
                                } else if(line.Length >= 11) {
                                    data.Context = line.Substring(9, line.Length - 10);
                                }
                            }
                            break;
                    }
                }
            }
            return data;
        }

        /// <summary>
        /// Clones this instance.
        /// </summary>
        /// <returns></returns>
        public POMetaData Clone() {
            POMetaData clone = new POMetaData();
            clone.Context = this.context;
            clone.ExtractedComments = this.ExtractedComments;
            clone.TranslatorsComments = this.TranslatorsComments;
            clone.References.AddRange(this.References);
            clone.Flags.AddRange(this.Flags);
            clone.UntranslatedString = this.UntranslatedString;
            clone.TranslatedString = this.TranslatedString;
            clone.UntranslatedPlural = this.UntranslatedPlural;
            clone.TranslatedPlurals = this.TranslatedPlurals;
            return clone;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string strPropertyName) {
            if(PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs(strPropertyName));
            }
        }
    }
}